package com.lxch.gdwxp.wxpay.service;

import com.github.wxpay.sdk.WXPayUtil;
import com.lxch.gdwxp.wxpay.porperties.SignParamConstant;
import com.lxch.gdwxp.wxpay.porperties.WXPayParams;
import com.lxch.gdwxp.wxpay.porperties.WXPayProperties;
import com.lxch.gdwxp.wxpay.utils.HttpRequestUtil;
import com.lxch.gdwxp.wxpay.utils.MapUtils;
import com.lxch.gdwxp.wxpay.wxpayconfig.WXPConstants;
import net.sf.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付业务层
 * 支付业务 主要是这个类来完成
 */
public class WXPayService {
    private final static Logger log = LoggerFactory.getLogger(WXPayService.class);

    private WXPayProperties wxPayProperties;

    public void setWxPayProperties(WXPayProperties wxPayProperties) {
        this.wxPayProperties = wxPayProperties;
    }

    public WXPayProperties getWxPayProperties() {
        return wxPayProperties;
    }

    /**
     * 拼接成微信api规定格式的数据 通知微信 这边已经接收到了微信付款成功回调通知
     */
    public static String notifyWX(String return_code, String return_msg) {
        return "<xml>" + "<return_code>" + return_code + "</return_code>" + "<return_msg>" + return_msg + "</return_msg>" + "</xml>";
    }

    /**
     * 调用微信获取OppenId的api
     *
     * @param code 拉取用户oppenId 的api接口需要的 用户code
     * @return 返回一个Map成功status:200,oppenId:oppenid,access_token:token 失败status:400,msg:错误消息
     */
    public Map<String, Object> setOppenId(String code) {
        // 替换授权URL  oauth_url 中的APPID SECRET code
        String oauth_url = WXPConstants.oauth_url
                .replace("APPID", wxPayProperties.getAPPID())
                .replace("SECRET", wxPayProperties.getAPPSECRET())
                .replace("CODE", code);
        log.info("=================oauth_url:=======" + oauth_url);
        // 发起一个微信获取用户oppenId的api请求 获取到的数据转换成 json格式数据，HttpRequestUtil 封装发起微信api请求的的工具
        JSONObject jsonObject = HttpRequestUtil.httpsRequestToJsonObject(oauth_url, "GET", null);
        log.info("============调用setOppenId接口得到的========jsonObject:" + jsonObject);
        Object errorCode = jsonObject.get("errcode");
        Map<String, Object> resultMap = new HashMap<>();
        // 根据code 获取 openid 如果 errCode有说明 出错
        if (errorCode != null) {
            log.info("==============获取openid出错,原因：" + errorCode);
            resultMap.put("status", 400);
            resultMap.put("msg", "获取oppenId出错 ，原因：" + errorCode);
        } else {
            String oppenId = jsonObject.getString("openid");
            log.info("========================获取oppenid成功oppenid:" + oppenId);
            resultMap.put("access_token", jsonObject.getString("access_token"));//返回access_token 后面需要获取用户信息就用这个
            resultMap.put("status", 200);
            resultMap.put("oppenId", oppenId);
        }
        return resultMap;
    }

    /**
     * 封装微信支付统一下单接口的请求参数
     *
     * @param body             自定义数据，可以是商品名
     * @param device_info      设备号终端设备号
     * @param fee_type         支付币种
     * @param oppenId          用户oppenId
     * @param out_trade_no     商户系统内部订单号
     * @param product_id       商品id 当trade_type=NATIVE时（即扫码支付），此参数必传。此参数为二维码中包含的商品ID，商户自行定义
     * @param spbill_create_ip 终端ip 用户端ip\
     * @param time_start       交易开始时间
     * @param time_expire      交易结束时间
     * @param total_fee        交易金额
     * @param trade_type       支付方式 JSAPI 扫码等
     * @return 统一下单接口返回值的Map对象
     */
    public Map<String, String> reqParam(String body, String device_info, String fee_type, String oppenId,
                                        String out_trade_no, String product_id, String spbill_create_ip,
                                        String time_start, String time_expire, String total_fee, String trade_type) throws
            InvocationTargetException, IllegalAccessException {
        //使用了自己封装请求参数的类，避免写参数名
        WXPayParams params = new WXPayParams();
        params.setBody(body);
        params.setDevice_info(device_info);
        params.setFee_type(fee_type);
        params.setNotify_url(wxPayProperties.getNOTIFY_URL());
        System.out.println("============调用统一下单接口的用户oppenId==" + oppenId);
        params.setOpenid(oppenId);
        System.out.println("==============正在支付的订单：" + out_trade_no);
        params.setOut_trade_no(out_trade_no);
        params.setProduct_id(product_id);

        System.out.println("=================使用CusAccessObjectUtil工具类从页面中解析的用户端IP:" + spbill_create_ip);
        params.setSpbill_create_ip(spbill_create_ip);
        params.setTime_start(time_start);
        params.setTime_expire(time_expire);
        params.setTotal_fee(total_fee);
        params.setTrade_type(trade_type);

        // * 把准备好的参数 放到map中
//        Map<String, String> data = new HashMap<>();
        Map map = MapUtils.java2Map(params);
        map.remove("time_start");//不设置订单开始结束时间
        map.remove("time_expire");//
        log.info("================================wxpayservice122行：微信支付统一下单请求参数" + map);
        return map;
    }

    /**
     * 处理统一下单 返回参数
     *
     * @param respResult   统一下单 返回参数
     * @param out_trade_no 调用者
     * @return 下单状态 成功或失败 status=200 为成功  失败 status=400,err_code_des=错误描述
     * @throws Exception
     */
    public Map<String, Object> respResultHandle(Map<String, String> respResult, String out_trade_no) throws Exception {

        Map<String, Object> resultMap = new HashMap<>();
        // 获取微信支付返回信息 return_code 是否为sucsses
        String return_code = respResult.get("return_code");
        if (return_code.equals("SUCCESS")) {
            String result_code = respResult.get("result_code");
            if (result_code.equals("SUCCESS")) {
                log.info("订单：" + out_trade_no + "调用=============wxpayservice调用 统一下单接口成功======");
                resultMap.put("status", 200);
                resultMap.put("appid", wxPayProperties.getAPPID());//appid给后面使用
            } else {// result_code失败，获取错误描述
                resultMap.put("status", 400);
                resultMap.put("err_code_des", respResult.get("err_code_des"));
                log.info(out_trade_no + "===========下单失败 错误描述：" + respResult.get("err_code_des"));
            }
        } else {// return_code失败，获取错误描述 保存到 错误页面
            resultMap.put("status", 400);
            resultMap.put("err_code_des", respResult.get("return_msg"));
            log.info("订单：" + out_trade_no + "调用统一下单失败 原因：" + respResult.get("return_msg") + "wxpayservice153行返回值：" + respResult);
        }
        return resultMap;
    }

    /**
     * 生成公众号支付JSAPI需要的签名sign
     *
     * @param prepay_id 生成sign需要的参数 统一下单接口返回的一个参数
     * @param nonceStr  生成sign需要的参数 32位随机数
     * @param timeStamp 生成sign需要的参数 时间戳
     * @return sign
     * @throws Exception 生成签名时发生的异常
     */
    public Map<String, String> getJSAPISig(String prepay_id, String nonceStr, String timeStamp) throws Exception {

        Map<String, String> payMap = new HashMap<String, String>();
        payMap.put(SignParamConstant.APPID, wxPayProperties.getAPPID());
        payMap.put(SignParamConstant.TIMESTAMP, timeStamp);
        payMap.put(SignParamConstant.NONCESTR, nonceStr);
        payMap.put(SignParamConstant.PACKAGE, "prepay_id=" + prepay_id);
        payMap.put(SignParamConstant.SIGNTYPE, "MD5");
        //生成签名
        String paySign = WXPayUtil.generateSignature(payMap, wxPayProperties.getKEY());
        payMap.clear();
        payMap.put("sign", paySign);
        payMap.put("appId", wxPayProperties.getAPPID());
        return payMap;
    }

    /**
     * 扫码支付
     *
     * @param out_trade_no 调用者
     * @param respResult   统一下单 返回参数
     * @return 能生成支付二维码的 URL code_url
     */
    public String NATIVEPay(String out_trade_no, Map<String, String> respResult) {
        log.info("订单号：" + out_trade_no + "调用 统一下单接口成功 生成支付二维码");
        String code_url = respResult.get("code_url");
        return code_url;
    }

    /**
     * 组装getcode的地址
     *
     * @return
     */
    public String getCodeUrl() {
        // 请求会到一个自定义的放到服务器根路径中的中转页面get-weixin-code.html 自定义页面会请求授权，授权后跳转的地址是 获取openid的
        System.out.println(wxPayProperties);
        String code_url = WXPConstants.code_url.replace("APPID", wxPayProperties.getAPPID());
        // 重定向 到授权地址 此地址 会跳转到 获取openid controller
        System.out.println("=================生成code_url=" + code_url);
        return code_url;
    }

    /**
     * 组装userinfo_url的地址
     *
     * @return
     */
    public String getUserinfoURL(String accessToken) {
        // 请求会到一个自定义的放到服务器根路径中的中转页面get-weixin-code.html 自定义页面会请求授权，授权后跳转的地址是 获取openid的
        System.out.println(wxPayProperties);
        String code_url = WXPConstants.userinfo_url.replace("OPPENID", wxPayProperties.getAPPID());
        // 重定向 到授权地址 此地址 会跳转到 获取openid controller
        System.out.println("=================生成code_url=" + code_url);
        return code_url;
    }

    /**
     * 处理用户支付后回调的返回参数
     *
     * @param resultMap 用户支付后的返回值
     * @return 用户支付后结果 是否支付成功  成功为status=200 失败status=502/501 msg=失败原因
     * @throws Exception 生成签名异常
     */
    public Map<String, String> respResultHandle(Map<String, String> resultMap) throws Exception {

        Map<String, String> returnMap = new HashMap<>();
        System.out.println("处理用户支付后的返回值=================" + resultMap);
        if (resultMap.get("return_code").equalsIgnoreCase("SUCCESS")) {
            // 判断签名是否正确，正确就开启购买会员相关业务 错误说明 交易有猫腻 不开启业务并报警
            if (WXPayUtil.isSignatureValid(resultMap, wxPayProperties.getKEY())) {
                returnMap.put("status", "200");
            } else {// 判断签名失败 数据被篡改 中断业务
                returnMap.put("status", "502");
                returnMap.put("msg", "判断签名失败");
            }
        } else {// 支付失败 显示失败信息
            returnMap.put("status", "501");
            returnMap.put("msg", "微信支付结果返回的不是success");
        }
        System.out.println("处理用户支付后的返回值=================处理后结果" + returnMap);
        return returnMap;
    }
}